#! /usr/bin/python
import os,subprocess

COPY_DEST_PATH  = "/home/nfs"
SRC_TARGET_NAME = "sys"
MAKE            = "/usr/bin/make"
MAKE_LOG_FILE   = "make_log.txt"
VERSION         = {'r':'Release', 'd':'Debug'}
BOARDS          = {'0':"HI3531", '1':"HI3521", '2':"HI3520A", '3':"HI3520D", '4':"HI3520A_UCLIBC", '5':"HI3521_UCLIBC"}
SPECIAL_DIRS    = {'link':'LINK_DIR'}

# This function is designed to execute shell cmd.
# Default behaviour is executing shell cmd with standard output and standard error(with is_stdout=True)
# If the argument is_stdout is set to "False", it will cache the output and error in ret_stdout,ret_stderr
def exec_shell_cmd(cmd, is_stdout=True):
    ret_val,ret_stdout,ret_stderr = (None,None,None)
    if not cmd: return (ret_val, ret_stdout, ret_stderr)
    try:
        if is_stdout:
            ret_val = subprocess.Popen(cmd, shell=True, stdout=None).wait()
        else:
            p1 = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
            ret_val = p1.wait()
            (ret_stdout,ret_stderr) = p1.communicate()
    except KeyboardInterrupt:
        print "\n==== User interrupt cmd's process! ===="
    except OSError or ValueError:
        print "Error: Cannot execute this command!"
    return (ret_val, ret_stdout, ret_stderr)

def copy_target_to_nfs(src_path):
    if not COPY_DEST_PATH: return 0
    src_path = src_path.strip()
    stdout = exec_shell_cmd("basename %s" % src_path, False)[1]
    if stdout and stdout[0:5] == "build":
        return exec_shell_cmd("cp -v %s/%s %s" % (src_path, SRC_TARGET_NAME, COPY_DEST_PATH))[0]
    return 0
    
def exec_make_cmd(make_cmd):
    ret = exec_shell_cmd(make_cmd)[0]
    if ret != 0 or exec_shell_cmd("grep -e '\*\*\*' make_log.txt | wc -l", False)[1] != '0\n':
        print "\n############################################"
        print "        Target build failed!    "
        print "############################################"
        return -1
    else:
        print "\n============================================"
        print "        Target build successfully!    "
        print "============================================"
        return 0

def parse_make_cmd(cmd_input):
    length = len(cmd_input)
    version_key, board_key = (cmd_input[1], cmd_input[2])
    cmd_part1, cmd_part2 = ('', '')
    special_dir = ''
    
    if length == 3:
        pass
    elif length >= 5 and cmd_input[3] == ' ':
        special_argv = cmd_input[4:].strip()
        if special_argv in SPECIAL_DIRS.keys():
            try:
                special_dir = os.environ[SPECIAL_DIRS[special_argv]]
            except IndexError:
                print "Error: Shell environment has no this variable:%s" %(SPECIAL_DIRS[special_argv])
                return -1
        elif special_argv[0:4] == "dir=":
            special_dir = special_argv[4:].strip()
            if not os.path.isdir(special_dir):
                print "Error: Please check the dir path"
                return -1
        else:
            print "Error: Please check the second parameter"
            return -1
    else:
        print "Error: Please check the second parameter"
        return -1
        
    if VERSION[version_key] == 'Debug':
        cmd_part1 = "%s BOARD=%s DEBUG=y 2>&1 |tee %s; exit ${PIPESTATUS[0]}" %(MAKE, BOARDS.get(board_key), MAKE_LOG_FILE)
    elif VERSION[version_key] == 'Release':
        cmd_part1 = "%s BOARD=%s 2>&1 |tee %s; exit ${PIPESTATUS[0]}" %(MAKE, BOARDS.get(board_key), MAKE_LOG_FILE)
    if special_dir: cmd_part2 = "cd %s" %(special_dir) + '; ' + cmd_part1
    
    #execute make cmd 1
    if exec_make_cmd(cmd_part1) != 0: return -1
    copy_target_to_nfs(exec_shell_cmd("pwd", False)[1])
    
    #execute make cmd 2
    if cmd_part2:
        print "\n------------ Start to build the second dir ------------"
        if exec_make_cmd(cmd_part2) != 0: return -1
        copy_target_to_nfs(special_dir)
    return 0

def get_ftp_file():
    try:
        cmd = "%s/DownloadLib.py" %(os.environ["SCRIPTS_DIR"])
    except IndexError:
        print "Error: Shell environment has no this variable:%s" %("SCRIPTS_DIR")
        return -1
    return exec_shell_cmd(cmd)[0]
    
def make_clean():
    cmd = "%s clean" %(MAKE)
    return exec_shell_cmd(cmd)[0]

def help_of_make_cmd():
    print '''
    SYNOPSIS
        m[v][n] [special_dir]
    
    DESCRIPTION
        m:
            The abbreviation of make
        [v]:
            Debug or Release version
            d: Debug
            r: Release
        [n]:
            Target board number, refer to the make menu, such as:
            0 :  HI3531
            1 :  HI3521
            2 :  HI3520A
        [special_dir]:
            After current dir built successfully, the dir we want to auto start make operation:
            link: the dir which named "build" under the top dir, can link out the ELF file sys.
            dir=xxxxx: special dir named "xxxx"(Note: must be relative path on current dir)
    
    EXAMPLE:   
        e.g.: md1
              This command means we want to make the current dir with debug version and 
              the board is specified to 1(refer to the make menu for the board name).
        e.g.: mr2 link
              This command means we want to make the current dir with release version,
              and the board is specified to 2(refer to the make menu for the board name).
              And after current dir make successfully, the command will auto start to 
              make the build dir,which is under the TOP_DIR.
        e.g.: md0 dir=../
              This command means we want to make the current dir with debug version,
              and the board is specified to 0(refer to the make menu for the board name).
              And after current dir make successfully, the command will auto start to 
              make the "../" dir.
              '''

def main_menu():
    #Calculate menu appearance
    part1_width = 9
    part2_width = 20
    for item in BOARDS.values():
        if len(item) + 2 > part1_width:
            part1_width = len(item) + 2
    
    #First, print make version row
    print "-"*(part1_width + part2_width)
    print " "*(part1_width),
    for each_version in sorted(VERSION.items(), key=lambda d:d[0], reverse = False):
        print "%-8s" %(each_version[1]),
    print "\n" + "-"*(part1_width + part2_width)
    
    #Second, print board and command row
    for each_board in sorted(BOARDS.items(), key=lambda d:d[0], reverse = False):
        print "%s" %(each_board[1]) + " "*(part1_width - len(each_board[1])),
        for each_version in sorted(VERSION.items(), key=lambda d:d[0], reverse = False):
            print "%-8s" %('m' + each_version[0] + each_board[0]),
        print ""
    print "-"*(part1_width + part2_width)
    print "%-3s :\tMake clean"         %('c')
    print "%-3s :\tGet ftp file"       %('g')
    print "%-3s :\tList menu again"    %('l')
    print "%-3s :\tHelp info"          %('h')
    print "%-3s :\tQuit"               %('q')
    
def main():
    #Display main menu
    main_menu()
    #Parse input
    while True:
        choice = raw_input('MainMenu:')
        choice = choice.strip()
        length = len(choice)
        if length == 0:
            continue
        elif length == 1:
            if choice[0] == 'q' or choice[0] == 'Q':
                break
            elif choice[0] == 'l' or choice[0] == 'L':
                main_menu()
            elif choice[0] == 'h' or choice[0] == 'H':
                help_of_make_cmd()
            elif choice[0] == 'c' or choice[0] == 'C':
                make_clean()
            elif choice[0] == 'g' or choice[0] == 'G':
                get_ftp_file()
            else:
                print "Wrong choice inputed"
        elif length >= 3:
            if ((choice[0] == 'm') and \
                (choice[1] in [each[0] for each in VERSION.items()]) and \
                BOARDS.get(choice[2])):
                parse_make_cmd(choice)
            else:
                print "Wrong choice inputed"
        else:
            print "Wrong choice inputed"

if __name__ == "__main__":
    main()